package com.woniu.gateway.filter;

import cn.hutool.core.text.AntPathMatcher;
import com.woniu.core.exception.account.AccountException;
import com.woniu.core.exception.account.AccountExceptionCode;
import com.woniu.core.exception.token.TokenException;
import com.woniu.core.exception.token.TokenExceptionCode;
import com.woniu.core.util.JwtUtil;
import com.woniu.gateway.config.AuthenUrlsProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.TimeUnit;

//@Order(1)
@Component
public class UserAuthenticationFilter implements GlobalFilter {

    private AntPathMatcher apm = new AntPathMatcher();

    @Autowired
    private StringRedisTemplate srt;

    @Autowired
    private AuthenUrlsProperties urlConfig;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入网关过滤器");
        //排除公共不需要认证的请求
        String url = exchange.getRequest().getPath().toString();
        System.out.println("请求url:"+url);
        System.out.println("公共不需要认证的请求：" + urlConfig.getBaseUrls());
        if (match(urlConfig.getBaseUrls(),url)) return chain.filter(exchange);
        //排除所有后端请求
        String subFix = url.substring(url.lastIndexOf("."));
        if (subFix.equals(".api")) return chain.filter(exchange);
        //排除所有其他端请求
        if (subFix.equals(".admin")) return chain.filter(exchange);
        if (subFix.equals(".coach")) return chain.filter(exchange);
        if (subFix.equals(".gym")) return chain.filter(exchange);
        //排除所有不需要验证的用户端请求
        System.out.println("用户端不需要验证的请求：" + urlConfig.getUserUrls());
        if (match(urlConfig.getUserUrls(),url)) return chain.filter(exchange);

        System.out.println("开始用户端登录认证");
        List<String> tokens = exchange.getRequest().getHeaders().get("account_token");
        if (tokens == null || tokens.size() == 0) throw new TokenException(TokenExceptionCode.NO_LOGIN);
        else {
            String token = tokens.get(0);
            try {
                JwtUtil.parseToken(token,2);
            }catch (MalformedJwtException malformedJwtException){
                throw new AccountException(AccountExceptionCode.TOKEN_FORMAT_ERROR);
            }catch (ExpiredJwtException expiredJwtException){
                //token续期
                //用token取出长token，得到用户信息，再创建新的token
                String longToken = srt.opsForValue().get(token);
                if(longToken == null) throw new AccountException(AccountExceptionCode.TOKEN_STALE_DATED);
                //解析长token
                try {
                    //获取长token中的信息
                    Claims maps = JwtUtil.parseToken(longToken,2);
                    //重新创建新的token
                    String newToken =JwtUtil.createToken(maps,24,2);
                    exchange.getRequest().mutate().header("account_token",newToken).build();
                    exchange.getResponse().getHeaders().set("access",newToken);
                    exchange.getResponse().getHeaders().add("Access-Control-Expose-Headers","access");
                    //删除redis中存储的旧的token
                    srt.delete(token);
                    //将newToken传入redis,即重新设置redis里面的数据值
                    srt.opsForValue().set(newToken,longToken,24, TimeUnit.HOURS);
                } catch (AccountException accountException) {
                    throw new AccountException(AccountExceptionCode.TOKEN_STALE_DATED);
                }
            }catch (SignatureException signatureException){
                throw new AccountException(AccountExceptionCode.TOKEN_VISA_ERROR);
            }catch (Exception e) {
                throw new TokenException(TokenExceptionCode.TOKEN_ERI);
//                System.out.println(e);
            }
        }
        return chain.filter(exchange);
    }

    private Boolean match(List<String> urls, String url){
        if (urls == null || urls.size() == 0) return false;
        for (String u : urls) {
            if(apm.match(u, url)) return true;
        }
        return false;
    }
}
